home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 176-200 / scopedisk180 / arexxtutorial / minrexx / freedraw.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  42KB  |  1,130 lines

  1. #ifdef TALKTOREXX
  2. /*
  3.  *   This program is an example of how to add a Rexx port to a given
  4.  *   program.  I thought it particularly appropriate to grab a program
  5.  *   off Fred Fish Disk 1.  All the REXX stuff is bracketed by `ifdef
  6.  *   TALKTOREXX', so you can identify it easily.  If you compile with
  7.  *   TALKTOREXX unset, you will get the default program with no REXX
  8.  *   port.
  9.  *
  10.  *   The REXX port on this program adds another 3K to the executable
  11.  *   size, but a lot of functionality comes with that.  You can draw
  12.  *   from Rexx, spawn macros from Rexx, etc.  But go to the next
  13.  *   TALKTOREXX for more information.
  14.  *
  15.  *   To run a rexx macro on startup, simply give that rexx macro as
  16.  *   part of the command line, as in
  17.  *
  18.  *      freedraw sample
  19.  *
  20.  *   or
  21.  *
  22.  *      freedraw bspline 20 100 20 20 280 20 280 100
  23.  *
  24.  *   All modifications are by Radical Eye Software, and all modifications
  25.  *   are placed in the public domain.
  26.  */
  27. #endif
  28. /************************************************************************/
  29. /***                FreeDraw - PD graphics for Amiga                  ***/
  30. /***                                                                  ***/
  31. /***      This is an extremely simple graphics editor which works in  ***/
  32. /***   the windowing environment of the Amiga.  It is very limited    ***/
  33. /***   in features, but I hope to add a lot more, and I would be      ***/
  34. /***   happy to receive assistance from anyone who wants to give it.  ***/
  35. /***      The basic idea of this program is to provide some minimal   ***/
  36. /***   image editing functions which can be used to develop images    ***/
  37. /***   for other programs.  I know there will be a lot of Paint type  ***/
  38. /***   type programs avaialable soon, but what are we supposed to use ***/
  39. /***   now?  The most important features to add now will probably be  ***/
  40. /***   those related to "cut and paste", disk srtorage and retrieval, ***/
  41. /***   and "single-pixel" editing like Mac's "fatbits".               ***/
  42. /***      I intend to use the IFF standard for the image storage and  ***/
  43. /***   retrieval and will be coding a "Files" menu soon.  The work    ***/
  44. /***   required for "cut and paste" should be almost trivial, but I   ***/
  45. /***   still may not get to it for a while.  Fatbits editing from one ***/
  46. /***   window to another involves some manipulations of the RastPorts ***/
  47. /***   which still elude me, as I have only recently begun to use the ***/
  48. /***   Amiga and don't yet understand some important details of these ***/
  49. /***   structures.  This would be a great item for one of the genius  ***/
  50. /***   members of the Amiga programming community to provide.         ***/
  51. /***      There are only two menu topics in this version, so using it ***/
  52. /***   is really quite easy.  Boxes are not allowed to be drawn in    ***/
  53. /***   areas outside of the window where border gadgets are located,  ***/
  54. /***   and the pen-draw mode also clips to these same boundaries.  If ***/
  55. /***   you have begun to draw a box by clicking the left button while ***/
  56. /***   the cursor is located in the FreeDraw window, then you can     ***/
  57. /***   cancel that box by clicking the right button.  In the pen mode ***/
  58. /***   pressing and holding the left button will draw.   Colors are   ***/
  59. /***   selected by simply releasing the menu button over the desired  ***/
  60. /***   color in the Color menu.   The erase feature always clears the ***/
  61. /***   window to the currently selected color.                        ***/
  62. /***      This is no gem of programming style, but you're getting it  ***/
  63. /***   for the right price so be patient with its design flaws.  New  ***/
  64. /***   versions will appear here on BIX as soon as I can get them in  ***/
  65. /***   shape for release.  I apologize to anyone who objects to my    ***/
  66. /***   lack of coding grace, but I just want to get the project off   ***/
  67. /***   the ground, and improvements will be forthcoming.  There are   ***/
  68. /***   a lot of comments, but I didn't know what needed to be made    ***/
  69. /***   clear so I just commented everything.                          ***/
  70. /***                                                                  ***/
  71. /***      If you like the idea of a PD graphics program and would be  ***/
  72. /***   interested in doing some development work, then please write   ***/
  73. /***   me at the address listed below, or call if you prefer.  I do   ***/
  74. /***   want to know if there is any interest in such a project, so    ***/
  75. /***   I will be glad to discuss any ideas you might have.  Also, as  ***/
  76. /***   I do not currently use CompuServe or any other major nets, I   ***/
  77. /***   would appreciate if someone would post this listing there.     ***/
  78. /***      I hope somebody enjoys this.  Have Fun.                     ***/
  79. /***                                           Rick Ross 11/14/85     ***/
  80. /***                                                                  ***/
  81. /***        My address:                                               ***/
  82. /***                    Richard M. Ross, Jr.                          ***/
  83. /***                    Eidetic Imaging                               ***/
  84. /***                    740 N. 22nd Street                            ***/
  85. /***                    Philadelphia, PA  19130                       ***/
  86. /***                                                                  ***/
  87. /***                    Phone - (215) 236-7388                        ***/
  88. /************************************************************************/
  89. char *VERSION = "Freedraw 0.01 by Richard M. Ross" ;
  90. /*  compiler directives to fetch the necessary header files */
  91.  
  92. #include <exec/types.h>
  93. #include <exec/exec.h>
  94. #include <intuition/intuition.h>
  95. #include <intuition/intuitionbase.h>
  96. #include <graphics/gfx.h>
  97. #include <graphics/regions.h>
  98. #include <graphics/copper.h>
  99. #include <graphics/gels.h>
  100. #include <graphics/gfxbase.h>
  101. #include <devices/keymap.h>
  102. #include <hardware/blit.h>
  103.  
  104. /*   These definitions are used by intuition for
  105.  *   calls to OpenLibrary() in order to ensure
  106.  *   that an appropriate ROM revision is
  107.  *   available.
  108.  */
  109.  
  110. #define INTUITION_REV 1L
  111. #define GRAPHICS_REV  1L
  112.  
  113. /*   Intuition always wants to see these declarations */
  114. struct IntuitionBase *IntuitionBase;
  115. struct GfxBase *GfxBase;
  116.  
  117. /*   This is the Window structure declaration.
  118.  *   Nothing fancy is going on here, but note
  119.  *   the Flags and IDCMPFlags members of the
  120.  *   structure define which messages will be
  121.  *   sent by Intuition.  I haven't used them all
  122.  *   and if you want to change the settings you
  123.  *   should probably do it her instead of using
  124.  *   ModifyIDCMP later.
  125.  */
  126.  
  127. struct NewWindow NewWindow = {
  128.    10,
  129.    10,
  130.    600,
  131.    180,
  132.    0,
  133.    1,
  134.    CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK
  135.    | NEWSIZE | INACTIVEWINDOW,
  136.    WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG
  137.    | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE,
  138.    NULL,
  139.    NULL,
  140.    (UBYTE *)"AMIGA FreeDraw 0.01",
  141.    NULL,
  142.    NULL,
  143.    100, 35,
  144.    -1, -1,
  145.    WBENCHSCREEN,
  146. };
  147. #ifdef TALKTOREXX
  148. /*
  149.  *   We need our include file.
  150.  */
  151. #include "minrexx.h"
  152. /*
  153.  *   These are the REXX functions defined at the bottom of the file.
  154.  */
  155. void rexxcolor(), rexxbox(), rexxfbox(), rexxline(), rexxtofront(),
  156.     rexxtoback(), rexxexit(), rexxversion(), rexxspawn() ;
  157. int disp() ;
  158. /*
  159.  *   Here is our command association list.  Note that in this case,
  160.  *   we are setting the userdata field to be a function to call.
  161.  *   Dispatch will still take place through disp(), so common head
  162.  *   and tail stuff can go there.
  163.  *
  164.  *   Commands are all lower case, so we match either upper or lower.
  165.  *   (This is a requirement of minrexx.)
  166.  */
  167. struct rexxCommandList rcl[] = {
  168.    { "color", (APTR)&rexxcolor },
  169.    { "box", (APTR)&rexxbox },
  170.    { "fbox", (APTR)&rexxfbox },
  171.    { "line", (APTR)&rexxline },
  172.    { "tofront", (APTR)&rexxtofront },
  173.    { "toback", (APTR)&rexxtoback },
  174.    { "exit", (APTR)&rexxexit },
  175.    { "version", (APTR)&rexxversion },
  176.    { "spawn", (APTR)&rexxspawn },
  177.    { NULL, NULL } } ;
  178. #endif
  179. /*******************************************************************/
  180. /*      DrawBox - Simple routine to draw an unfilled rectangle     */
  181. /*   It accepts the  coordinates of the top-left and lower-right   */
  182. /*   points of the rectangle, a pointer to the Window structure,   */
  183. /*   and the color in which to render the rectangle.  The current  */
  184. /*   FgPen color of the window is preserved thru the call.  No     */
  185. /*   clipping is done.                                             */
  186. /*******************************************************************/
  187. void DrawBox( tlx, tly, brx, bry, window, color )
  188. SHORT tlx, tly;                  /* top-left x,y coordinates */
  189. SHORT brx, bry;                  /* lower-right x,y coordinates */
  190. struct Window *window;           /* pointer to target window */
  191. BYTE color;                      /* color to use for render */
  192.    {
  193.    BYTE OldColor = window->RPort->FgPen;   /* save window's FgPen */
  194.  
  195.    SetAPen( window->RPort, (long)color );        /* set draw color for box  */
  196.    Move(window->RPort, (long)tlx, (long)tly);          /* move to top-left point  */
  197.    Draw(window->RPort, (long)brx, (long)tly);          /* and draw to each of the */
  198.    Draw(window->RPort, (long)brx, (long)bry);          /* four corners of the box */
  199.    Draw(window->RPort, (long)tlx, (long)bry);
  200.    Draw(window->RPort, (long)tlx, (long)tly);
  201.    SetAPen( window->RPort, (long)OldColor );     /* restore old FgPen */
  202.    }
  203.  
  204.  
  205. /*********************************************************/
  206. /*                 Color Select Menu                     */
  207. /*                                                       */
  208. /*      This is where the menu for color selection is    */
  209. /*   defined.  It should be flexible enough to allow for */
  210. /*   increased palette sizes, but this version is only   */
  211. /*   for the 4-color mode of the WorkBench screen.       */
  212. /*********************************************************/
  213.  
  214. /*   A few definitions are needed here.
  215.  *   Note that MAXPAL should be increased
  216.  *   to allow for palette larger than
  217.  *   four colors.    
  218.  */
  219. #define ITEMSTUFF (ITEMENABLED | HIGHBOX)
  220. #define CW 40
  221. #define CH 25
  222. #define MAXPAL 4
  223.  
  224. /*   declare enough storage for required
  225.  *   number of menu items and associated
  226.  *   images.  This menu will be using
  227.  *   graphics renditions of menu items,
  228.  *   so the Image structures must be
  229.  *   declared.  This menu is modeled after
  230.  *   the one found in the IconEd source.
  231.  */
  232. struct MenuItem coloritem[MAXPAL];
  233. struct Image colorimage[MAXPAL];
  234.  
  235. /*   array of palette sizes to correspond with
  236.  *   depth of window in bit-planes
  237.  */
  238. SHORT palette[] = { 2, 4, 8, 16, 32 };
  239.  
  240.  
  241. /*****************************************************************/
  242. /*    The following function initializes the structure arrays    */
  243. /*   needed to provide the Color menu topic.                     */
  244. /*****************************************************************/
  245. InitColorItems( depth )
  246. SHORT depth;               /* number of bit-planes in window */
  247.    {
  248.    SHORT n, colors;
  249.  
  250.    colors = palette[depth-1];
  251.    for( n=0; n<colors; n++ )           /* loop for max number of items */
  252.       {
  253.       coloritem[n].NextItem = &coloritem[n+1];
  254.       coloritem[n].ItemFill = (APTR)&colorimage[n];
  255.       /*   the next two items might be changed for
  256.        *   when bit-planes is greater than 2
  257.        */
  258.       coloritem[n].LeftEdge = 2 + CW * (n % 4);
  259.       coloritem[n].TopEdge = CH * (n / 4);
  260.       coloritem[n].Width = CW;
  261.       coloritem[n].Height = CH;
  262.       coloritem[n].Flags = ITEMSTUFF;
  263.       coloritem[n].MutualExclude = 0;
  264.       coloritem[n].SelectFill = NULL;
  265.       coloritem[n].Command = 0;
  266.       coloritem[n].SubItem = NULL;
  267.       coloritem[n].NextSelect = 0;
  268.  
  269.       colorimage[n].LeftEdge = 1;
  270.       colorimage[n].TopEdge = 1;
  271.       colorimage[n].Width = CW-2;
  272.       colorimage[n].Height = CH-2;
  273.       colorimage[n].Depth = depth;
  274.       colorimage[n].ImageData = NULL;
  275.       colorimage[n].PlanePick = 0;
  276.       colorimage[n].PlaneOnOff = n;
  277.       }
  278.    coloritem[colors-1].NextItem = NULL;   /* needed for last item in list */
  279.    return( 0 );
  280.    }
  281.  
  282.  
  283. /*****************************************************/
  284. /*                Draw Mode Menu                     */
  285. /*                                                   */
  286. /*      Here are the code and data declarations for  */
  287. /*   the DrawMode menu.  Current choices are limited */
  288. /*   to Erase, Filled Box, Hollow Box, and PenDraw.  */
  289. /*****************************************************/
  290.  
  291. /* define maximum number of menu items */
  292. #define DMODEMAX 4
  293.  
  294. /*   declare storage space for menu items and
  295.  *   their associated IntuiText structures
  296.  */
  297. struct MenuItem DModeItem[DMODEMAX];
  298. struct IntuiText DModeText[DMODEMAX];
  299.  
  300. /*****************************************************************/
  301. /*    The following function initializes the structure arrays    */
  302. /*   needed to provide the DrawMode menu topic.                  */
  303. /*****************************************************************/
  304. InitDModeItems()
  305.    {
  306.    short n;
  307.  
  308.    /* initialize each meu item and IntuiText with loop */
  309.    for( n=0; n<DMODEMAX; n++ )
  310.       {
  311.       DModeItem[n].NextItem = &DModeItem[n+1];
  312.       DModeItem[n].LeftEdge = 0;
  313.       DModeItem[n].TopEdge = 10 * n;
  314.       DModeItem[n].Width = 112;
  315.       DModeItem[n].Height = 10;
  316.       DModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
  317.       DModeItem[n].MutualExclude = 0;
  318.       DModeItem[n].ItemFill = (APTR)&DModeText[n];
  319.       DModeItem[n].SelectFill = NULL;
  320.       DModeItem[n].Command = 0;
  321.       DModeItem[n].SubItem = NULL;
  322.       DModeItem[n].NextSelect = 0;
  323.  
  324.       DModeText[n].FrontPen = 0;
  325.       DModeText[n].BackPen = 1;
  326.       DModeText[n].DrawMode = JAM2;     /* render in fore and background */
  327.       DModeText[n].LeftEdge = 0;
  328.       DModeText[n].TopEdge = 1;
  329.       DModeText[n].ITextFont = NULL;
  330.       DModeText[n].NextText = NULL;
  331.       }
  332.    DModeItem[DMODEMAX-1].NextItem = NULL;
  333.  
  334.    /* initialize text for specific menu items */
  335.    DModeText[0].IText = (UBYTE *)"Erase All";
  336.    DModeText[1].IText = (UBYTE *)"Hollow Box";
  337.    DModeText[2].IText = (UBYTE *)"Filled Box";
  338.    DModeText[3].IText = (UBYTE *)"Pen Draw";
  339.  
  340.    return( 0 );
  341.    }
  342.  
  343.  
  344. /***************************************************/
  345. /*                Menu Definition                  */
  346. /*                                                 */
  347. /*      This section of code is where the simple   */
  348. /*   menu definition goes.  For now it supports    */
  349. /*   only Color and Drawmode selection, but new    */
  350. /*   choices can easily be added by creating       */
  351. /*   structures and initializations functions      */
  352. /*   similar to those provided above.              */
  353. /***************************************************/
  354.  
  355. /* current number of available menu topics */
  356. #define MAXMENU 2
  357.  
  358. /*   declaration of menu structure array for
  359.  *   number of current topics.  Intuition
  360.  *   will use the address of this array to
  361.  *   set and clear the menus associated with
  362.  *   the window.
  363.  */
  364. struct Menu menu[MAXMENU];
  365.  
  366. /**********************************************************************/
  367. /*   The following function initializes the Menu structure array with */
  368. /*  appropriate values for our simple menu strip.  Review the manual  */
  369. /*  if you need to know what each value means.                        */
  370. /**********************************************************************/
  371. InitMenu()
  372.    {
  373.    menu[0].NextMenu = &menu[1];
  374.    menu[0].LeftEdge = 10;
  375.    menu[0].TopEdge = 0;
  376.    menu[0].Width = 50;
  377.    menu[0].Height = 10;
  378.    menu[0].Flags = MENUENABLED;
  379.    menu[0].MenuName = "Color";           /* text for menu-bar display */
  380.    menu[0].FirstItem = &coloritem[0];    /* pointer to first item in list */
  381.  
  382.    menu[1].NextMenu = NULL;
  383.    menu[1].LeftEdge = 65;
  384.    menu[1].TopEdge = 0;
  385.    menu[1].Width = 85;
  386.    menu[1].Height = 10;
  387.    menu[1].Flags = MENUENABLED;
  388.    menu[1].MenuName = "DrawMode";        /* text for menu-bar display */
  389.    menu[1].FirstItem = &DModeItem[0];    /* pointer to first item in list */
  390.  
  391.    return( 0 );
  392.    }
  393.  
  394.  
  395. /******************************************************/
  396. /*                   Main Program                     */
  397. /*                                                    */
  398. /*      This is the main body of the program.         */
  399. /******************************************************/
  400.  
  401. struct Window *Window;              /* ptr to applications window */
  402. SHORT MinX, MinY, MaxX, MaxY;       /* clipping boundary variables */
  403. SHORT KeepGoing = TRUE;             /* main loop control value */
  404.  
  405. main(argc, argv)
  406. int argc ;
  407. char *argv[] ;
  408.    {
  409.    struct Library *OpenLibrary() ;
  410.    struct Window *OpenWindow() ;
  411.    struct Message *GetMsg() ;
  412.    struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
  413.    BYTE DrawColor = 1;                 /* initial drawing color */
  414.    SHORT OldBRX = 30, OldBRY = 30;     /* point coords used for boxes */
  415.    SHORT TLX = 20, TLY = 20;           /* initial top-left point coords */
  416.    ULONG class;                        /* used in message monitor loop */
  417.    USHORT code;                        /* used in message monitor loop */
  418.    SHORT x, y, x1, y1, x2, y2;         /* various coordinate variables */
  419.    USHORT MenuNum, ItemNum;
  420.    /*   The following is a set of declarations
  421.     *   for a number of flag values used by the
  422.     *   program.  These would perhaps be better
  423.     *   coded as a bit-field for all the flags,
  424.     *   but I'm lazy, and this is easier.
  425.     */
  426.    SHORT MouseMoved = FALSE;     /* indicates new mouse position ready */
  427.    SHORT ClipIt = FALSE;         /* are new point coords out of bounds? */
  428.    SHORT ClippedLast = FALSE;    /* was last PenDraw operation clipped? */
  429.    SHORT PenMode = FALSE;        /* indicates PenDraw mode is set */      
  430.    SHORT PenDown = FALSE;        /* if mouse moved, then should it draw? */
  431.    SHORT RubberBox = FALSE;      /* are we currently rubberbanding a box? */
  432.    SHORT FilledBox = FALSE;      /* should boxes be filled when drawn? */
  433. #ifdef TALKTOREXX
  434. /*
  435.  *   If we are talking to REXX, we need these two additional locals.
  436.  */
  437.    long rexxbit ;
  438.    char firstcommand[256] ;
  439. #endif
  440.  
  441.    /* attempt to Open Library to access Intuition */
  442.    IntuitionBase = (struct IntuitionBase *)
  443.       OpenLibrary("intuition.library", INTUITION_REV);
  444.    if( IntuitionBase == NULL )
  445.       exit(FALSE);
  446.  
  447.    /* attempt to OpenLibrary to access Graphics functions */
  448.    GfxBase = (struct GfxBase *)
  449.       OpenLibrary("graphics.library",GRAPHICS_REV);
  450.    if( GfxBase == NULL )
  451.       exit(FALSE);
  452.  
  453.  
  454.    /* Try to open new window for application */
  455.    if(( Window = OpenWindow(&NewWindow) ) == NULL)
  456.       exit(FALSE);
  457.  
  458.    /*   set initial clipping boundaries
  459.     *   from the values found in the window
  460.     *   structure for border dimensions
  461.     */
  462.    MinX = Window->BorderLeft;
  463.    MinY = Window->BorderTop;
  464.    MaxX = Window->Width - Window->BorderRight - 1;
  465.    MaxY = Window->Height - Window->BorderBottom - 1;
  466.  
  467.    InitColorItems( 2 );         /* initialize Color menu arrays */
  468.    InitDModeItems();            /* initialize DrawMode menu arrays */
  469.    InitMenu();                  /* initialize the menu structures */
  470.  
  471.    /*   Now, having initialized the various arrays
  472.     *   of structures required for menu generation
  473.     *   we can tell Intuition to make our menus
  474.     *   available to the user when this window
  475.     *   is active.
  476.     */
  477.    SetMenuStrip( Window, &menu[0] );
  478.  
  479.    /* set initial drw mode and color */
  480.    SetDrMd( Window->RPort, JAM1 );
  481.    SetAPen( Window->RPort, DrawColor );
  482. #ifdef TALKTOREXX
  483. /*
  484.  *   For rexx, we open up a Rexx port, and send out the first command,
  485.  *   if there was one.  We send it out asynchronously; no reason not to.
  486.  */
  487.    rexxbit = upRexxPort("freedraw", rcl, "fd", &disp) ;
  488.    firstcommand[0] = 0 ;
  489.    for (x=1; x<argc; x++) {
  490.       strcat(firstcommand, argv[x]) ;
  491.       strcat(firstcommand, " ") ;
  492.    }
  493.    if (firstcommand[0]) {
  494.       asyncRexxCmd(firstcommand) ;
  495.    }
  496. #endif
  497.    /*   Everything the program needs is now
  498.     *   initialized and put in place.  The
  499.     *   program enters the following loop
  500.     *   and processes message continuously as
  501.     *   they are received from Intuition.
  502.     *      I guess this loop is the real workhorse
  503.     *   of the program.  By the way, the loop
  504.     *   control variable KeepGoing remains TRUE
  505.     *   until a CLOSEWINDOW message is received.
  506.     *   At that point it goes FALSE, and the
  507.     *   program cleans up and exits.
  508.     */
  509.    while( KeepGoing )
  510.       {
  511.  
  512.       /* stay here until a message is received from Intuition */
  513. #ifdef TALKTOREXX
  514. /*
  515.  *   If we're working with Rexx, we wait on the Rexx bit as well.
  516.  *   Then, we handle any Rexx messages.
  517.  */
  518.       Wait( (1L << Window->UserPort->mp_SigBit) | rexxbit);
  519.       dispRexxPort() ;
  520. #else
  521.       Wait( 1L << Window->UserPort->mp_SigBit);
  522. #endif
  523.       MouseMoved = FALSE;    /* clear this flag each time thru loop */
  524.  
  525.       /*   since more than one message may be waiting
  526.        *   a reply at this point, a loop is used to
  527.        *   process all that have come in until no more
  528.        *   are ready.  Msg received is assigned to
  529.        *   NewMessage from the GetMsg() function.  This
  530.        *   value will be NULL if no message is ready,
  531.        *   and control passes out of the loop at that time
  532.        */
  533.       while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
  534.          {
  535.  
  536.          /*   copy some values from the message structure
  537.           *   to variables used in the switch statements
  538.           *   below
  539.           */
  540.          class = NewMessage->Class;
  541.          code = NewMessage->Code;
  542.          x = Window->MouseX;
  543.          y = Window->MouseY;
  544.  
  545.          /*   SIZEVERIFY is a very high priority message
  546.           *   in our loop and requires some immediate
  547.           *   servicing.  Any outstanding draw operations
  548.           *   are immediately cancelled, and the DrawMode
  549.           *   is nulled.  This prevents any attempts to
  550.           *   render outside whatever new Window boundaries
  551.           *   the user chooses.
  552.           *
  553.           *   (not anymore, it don't.  -tgr)
  554.  
  555.          if( class == SIZEVERIFY )
  556.             {
  557.             PenDown = FALSE;
  558.             if( RubberBox )
  559.                {
  560.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  561.                Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  562.                RubberBox = FALSE;
  563.                }
  564.             }
  565.           */
  566.  
  567.          /*   we have all the information needed from
  568.           *   the message, so we can now safely reply
  569.           *   to it without losing data
  570.           */
  571.          ReplyMsg( NewMessage );
  572.  
  573.          /*  Examine point coords from message received
  574.           *  and set the clipping flag if out of bounds.
  575.           *  If user was drawing in PenMode when message
  576.           *  was received, then the ClippedLast flag
  577.           *  should also be set to indicate this to the
  578.           *  next draw operation.
  579.           */
  580.          if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY ))
  581.             if( PenDown )
  582.                ClippedLast = TRUE;
  583.  
  584.  
  585.          /* enter switch on type of message received */
  586.          switch( class )
  587.          {
  588.             case MOUSEMOVE:
  589.                /*   Don't really do anything with this one
  590.                 *   until any other, more important, messages
  591.                 *   are received and processed.
  592.                 */
  593.                MouseMoved = TRUE;
  594.                break;
  595.  
  596.             case NEWSIZE:
  597.                /*  set new clipping boundaries */
  598.                MinX = Window->BorderLeft;
  599.                MinY = Window->BorderTop;
  600.                MaxX = Window->Width - Window->BorderRight - 1;
  601.                MaxY = Window->Height - Window->BorderBottom - 1;
  602.                break;
  603.  
  604.             case CLOSEWINDOW:
  605.                /*   User is ready to quit, so indicate
  606.                 *   that execution should terminate
  607.                 *   with next iteration of the loop.
  608.                 */
  609.                KeepGoing = FALSE;
  610.                break;
  611.  
  612.             case MOUSEBUTTONS:
  613.                /*   A number of things could have happened
  614.                 *   here, and further examination of data
  615.                 *   received from message is needed to
  616.                 *   determine what action should be taken.
  617.                 *   The code variable holds important info
  618.                 *   about what actually caused the message
  619.                 *   to be sent in the first place.
  620.                 */
  621.                switch ( code )
  622.                   {
  623.                   case SELECTUP:
  624.                      /*   User was holding down the left button
  625.                       *   and just released it.  The PenMode
  626.                       *   flag variables are set accordingly.
  627.                       *   The pen can no longer be down, and
  628.                       *   ClippedLast is reset for next time.
  629.                       */
  630.                      PenDown = ClippedLast = FALSE;
  631.                      break;
  632.  
  633.                   case SELECTDOWN:
  634.                      /*   User has pressed the left button, and
  635.                       *   several differnt actions may need to
  636.                       *   be taken.  If the ClipIt value is TRUE,
  637.                       *   then no action should be taken at all.
  638.                       */
  639.                      if( ClipIt )
  640.                         break;
  641.  
  642.                      /*   If user is currently in PenMode, then
  643.                       *   set up to draw when MOUSEMOVED messages
  644.                       *   are received until a subsequent SELECTUP
  645.                       *   message comes in.
  646.                       */
  647.                      if( PenMode )
  648.                         {
  649.                         PenDown = TRUE;
  650.                         ClippedLast = FALSE;
  651.  
  652.                         /* make sure to set appropriate mode */
  653.                         SetDrMd( Window->RPort, JAM1 );
  654.  
  655.                         /* and establish initial position to draw */
  656.                         Move( Window->RPort, (long)x, (long)y );
  657.                         break;
  658.                         }
  659.  
  660.                      /*   If user is currently rubberbanding a box,
  661.                       *   then a SELECTDOWN message means it is time
  662.                       *   to stop rubberbanding and actually draw it.
  663.                       *   The following code will be executed if
  664.                       *   this is the case, and it will determine if
  665.                       *   a filled box is needed before rendering.
  666.                       */
  667.                      if( RubberBox )
  668.                         {
  669.                         /*   set draw mode back to JAM1 since
  670.                          *   it is now currently set to COMPLEMENT
  671.                          */
  672.                         SetDrMd( Window->RPort, JAM1 );
  673.                         RubberBox = FALSE;   /* turn off rubberbanding */
  674.  
  675.                         /*   Restore the condition of the RMBTRAP
  676.                          *   bit in the Window structure's Flags
  677.                          *   member.  Menubutton events will no
  678.                          *   be received by this loop.
  679.                          */
  680.                         Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  681.  
  682.                         /*   RectFill is not condusive to the smooth
  683.                          *   execution of programs iit arguments are
  684.                          *   out of order, sot his code sorts them
  685.                          *   in preparation for the call.
  686.                          */
  687.                         if( FilledBox )
  688.                            {
  689.                            /* first sort the x-coords */
  690.                            if( TLX < OldBRX )  {
  691.                               x1 = TLX;  x2 = OldBRX;  }
  692.                            else  {
  693.                               x1 = OldBRX;  x2 = TLX;  }
  694.  
  695.                            /* then sort the y-coords */
  696.                            if( TLY < OldBRY )  {
  697.                               y1 = TLY;  y2 = OldBRY;  }
  698.                            else  {
  699.                               y1 = OldBRY;  y2 = TLY;  }
  700.  
  701.                            /* now generate the filled rectangle */
  702.                            RectFill( Window->RPort, (long)x1, (long)y1,
  703.                                                     (long)x2, (long)y2 );
  704.                            }
  705.                         else
  706.                            {
  707.                            /* FilledBox not set, so draw hollow box */
  708.                            DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  709.                            }
  710.                         break;
  711.                         }
  712.  
  713.                      /*   If execution comes here, then PenMode was
  714.                       *   not set and user was not rubberbanding.
  715.                       *   SELECTDOWN therefore indicates to start the
  716.                       *   rubberbanding process at this point.  The
  717.                       *   initial coords are set to the values we
  718.                       *   received when the GetMsg() was executed.
  719.                       */
  720.                      TLX = OldBRX = x;  TLY = OldBRY = y;
  721.  
  722.                      /* set to render in XOR mode */
  723.                      SetDrMd( Window->RPort, COMPLEMENT );
  724.  
  725.                      /* set flag to indicate we are now rubberbanding */
  726.                      RubberBox = TRUE;
  727.  
  728.                      /*   This instruction indicates to Intuition
  729.                       *   that we now wish to receive a message
  730.                       *   each time the Menubutton is pressed.
  731.                       *   This is how we hijack the right button
  732.                       *   for temporary use as a Cancel button
  733.                       *   instead of a Menubutton.
  734.                       */
  735.                      Window->Flags |= RMBTRAP;
  736.  
  737.                      /* render the initial rubberbox and exit */
  738.                      DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  739.                      break;
  740.  
  741.                   case MENUDOWN:
  742.                      /*   WE only receive this message class if
  743.                       *   the RMBTRAP flag bit has been set, so
  744.                       *   it always means that we should cancel
  745.                       *   the box which is currently rubberbanding.
  746.                       */
  747.                      /* turn the flag off */
  748.                      RubberBox = FALSE;
  749.  
  750.                      /* restore control of menubutton to Intuition */
  751.                      Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  752.  
  753.                      /*   erase (by double XOR'ing) the current
  754.                       *   rubberbox and exit switch.
  755.                       */
  756.                      DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  757.                      break;
  758.  
  759.                   default:
  760.                      /*   Something unimportant happened, so just
  761.                       *   continue thru the GetMsg() loop.
  762.                       */
  763.                      continue;
  764.                }
  765.                break;
  766.  
  767.             case MENUPICK:
  768.                /*   A menu event has taken place and is
  769.                 *   ready to be processed.  Examine the
  770.                 *   code variable received from the message
  771.                 *   to determine what action should be taken.
  772.                 *   The first check is for MENUNULL, which
  773.                 *   means that nothing should be done at all.
  774.                 */
  775.                if( code != MENUNULL )
  776.                   {
  777.                   /* get menu and item numbers from code */
  778.                   MenuNum = MENUNUM( code );
  779.                   ItemNum = ITEMNUM( code );
  780.  
  781.                   /* determine appropriate action by menu number */
  782.                   switch ( MenuNum )
  783.                      {
  784.                      case 0:
  785.                         /*   Menu 0 is the Color menu.  The
  786.                          *   item number indicates which new
  787.                          *   color to set.
  788.                          */
  789.                         DrawColor = ItemNum;
  790.                         SetAPen( Window->RPort, (long)DrawColor );
  791.                         break;
  792.  
  793.                      case 1:
  794.                         /*   Menu 1 is the DrawMode menu.  The item
  795.                          *   number indicates what to do.
  796.                          *   NOTE:  Since we cannot have received
  797.                          *   this message if we were rubberbanding,
  798.                          *   then there is no need to clean up before
  799.                          *   changing drawing modes.
  800.                          */
  801.                         switch ( ItemNum )
  802.                            {
  803.                            case 0:
  804.                               /* Erase window to current color */
  805.                               SetDrMd( Window->RPort, JAM1 );
  806.                               RectFill( Window->RPort, (long)MinX, (long)MinY,
  807.                                                        (long)MaxX, (long)MaxY);
  808.                               break;
  809.  
  810.                            case 1:
  811.                               /* set flag variables for hollow box */
  812.                               PenMode = FALSE;
  813.                               FilledBox = FALSE;
  814.                               break;
  815.  
  816.                            case 2:
  817.                               /* set flag variables for filled box */
  818.                               PenMode = FALSE;
  819.                               FilledBox = TRUE;
  820.                               break;
  821.  
  822.                            case 3:
  823.                               /* set flag variables for PenMode */
  824.                               PenMode = TRUE;
  825.                               break;
  826.  
  827.                            default:
  828.                               /* don't do anything */
  829.                               break;
  830.                            }
  831.                         break;
  832.  
  833.                      default:
  834.                         /* Menu number unrecognized, do nothing */
  835.                         break;
  836.                      }
  837.                   }
  838.                break;
  839.  
  840.             case INACTIVEWINDOW:
  841.                /*   User has de-selected our window, so a
  842.                 *   little bit of cleaning up may be needed
  843.                 *   to prevent untoward events when he comes
  844.                 *   back to it.
  845.                 */
  846.                /* erase any outstanding rubberbox */
  847.                if( RubberBox )
  848.                   DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  849.  
  850.                /* reset all the flafg variables */
  851.                PenDown = ClippedLast = RubberBox = FALSE;
  852.  
  853.                /* return possibly diverted menubutton events to Big I */
  854.                Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  855.                break;
  856.  
  857.             default:
  858.                /* message class was unrecognized, so do nothing */
  859.                break;
  860.             }
  861.          }   /* this brace ends the while(NewMessage) loop way back when */
  862.  
  863.       /*   There are no more messages waiting at the
  864.        *   IDCMP port, so we can now proceed to
  865.        *   process any MOUSEMOVED message we may
  866.        *   have received.
  867.        */
  868.       if( MouseMoved && !ClipIt)
  869.          {
  870.          /* the mouse did move, and we don't need to clip */
  871.  
  872.          /* check first if we are drawing in PenMode */
  873.          if( PenDown )
  874.             {
  875.             /*   We have to examine if we clipped the
  876.              *   last PenMode draw operation.  If we did,
  877.              *   then this is the first move back into
  878.              *   window boundaries, so we mov instead of
  879.              *   drawing.
  880.              */
  881.             if( ClippedLast )
  882.                {
  883.                ClippedLast = FALSE;         /* reset this flag now */
  884.                Move( Window->RPort, (long)x, (long)y );
  885.                }
  886.             else
  887.                Draw( Window->RPort, (long)x, (long)y ); /* draw to x,y coords */
  888.          }
  889.          else
  890.             {
  891.             /*   We weren't in PenMode, but we still might
  892.              *   be rubberbanding a box.  If so, then we
  893.              *   should erase the current rubberbox and
  894.              *   draw a new one with the new mouse coords.
  895.              */
  896.             if( RubberBox )
  897.                {
  898.                /* erase the old rubberbox - draw mode is COMPLEMENT */
  899.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  900.  
  901.                /* assign new values to box coords */
  902.                OldBRX = x;  OldBRY = y;
  903.  
  904.                /* and draw the new rubberbox */ 
  905.                DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
  906.                }
  907.             }
  908.          }
  909.       }
  910.  
  911.    /*   It must be time to quit, so we have to clean
  912.     *   up and exit.
  913.     */
  914. #ifdef TALKTOREXX
  915. /*
  916.  *   With Rexx, we need to bring the port down.  You might make this
  917.  *   part of exit() for programs that have multiple paths to exit.
  918.  */
  919.    dnRexxPort() ;
  920. #endif
  921.    ClearMenuStrip( Window );
  922.    CloseWindow( Window );
  923.    exit(TRUE);
  924.    }
  925. #ifdef TALKTOREXX
  926. /*
  927.  *   Now we get into the actual code necessary for our REXX port; functions
  928.  *   that do the real work.  Note that this program was not structured
  929.  *   particularly nicely for Rexx; I had to write each of these functions.
  930.  *   Many programs have these subroutines already in place; they are called
  931.  *   as part of the event loop.  This progam, however, just has one big
  932.  *   switch statement with different actions . . .
  933.  *
  934.  *   First, our locals.
  935.  */
  936. int currrexxcolor = 1 ;    /* what color is *rexx* drawing in? */
  937. int args[4] ;              /* what args did we see to this function? */
  938. int parsed ;               /* was argument parsing successful? */
  939. int userreplied ;          /* has the current message been replied to yet? */
  940. /*
  941.  *   This function takes a pointer to a pointer to a string, grabs the
  942.  *   next number, returns it, and advances the pointer to the string to
  943.  *   point after the number.
  944.  */
  945. int getnm(where)
  946. char **where ;
  947. {
  948.    register char *p = *where ;
  949.    register int val = 0 ;
  950.    int gotone = 0 ;
  951.  
  952.    while (*p <= ' ' && *p)
  953.       p++ ;
  954.    while ('0' <= *p && *p <= '9') {
  955.       gotone = 1 ;
  956.       val = 10 * val + *p++ - '0' ;
  957.    }
  958.    if (gotone == 0)
  959.       parsed = 0 ;
  960.    *where = p ;
  961.    return(val) ;
  962. }
  963. /*
  964.  *   This function trys to find `n' numeric arguments in the command
  965.  *   string, and stuffs them into the args array.
  966.  */
  967. void parseargs(p, n)
  968. char *p ;
  969. int n ;
  970. {
  971.    register int i ;
  972.  
  973.    while (*p > ' ' && *p)
  974.       p++ ;
  975.    for (i=0; i<n; i++)
  976.       args[i] = getnm(&p) ;
  977. }
  978. /*
  979.  *   This is our main dispatch function.  We check to make sure a Window
  980.  *   currently exists.  Then, we store away the `current color' and change
  981.  *   it to Rexx's current color, call our handler function, and then restore
  982.  *   the color.  If our handler replied, we return a 1 to indicate that.
  983.  *   If the parse and everything else was successful, we return a 0.
  984.  *   Otherwise, we return a failure of 20 to indicate that the arguments
  985.  *   were messed up.
  986.  */
  987. int disp(msg, dat, p)
  988. register struct RexxMsg *msg ;
  989. register struct rexxCommandList *dat ;
  990. char *p ;
  991. {
  992.    register int t ;
  993.  
  994.    parsed = 1 ;
  995.    if (Window) {
  996.       userreplied = 0 ;
  997.       t = Window->RPort->FgPen ;
  998.       SetAPen(Window->RPort, (long)currrexxcolor) ;
  999.       ((int (*)())(dat->userdata))(msg, p) ;
  1000.       SetAPen(Window->RPort, (long)t) ;
  1001.       if (! parsed)
  1002.          replyRexxCmd(msg, (long)parsed, 0L, NULL) ;
  1003.       return ;
  1004.    }
  1005.    replyRexxCmd(msg, 20L, 10L, NULL) ;
  1006. }
  1007. /*
  1008.  *   This handler sets the current rexx color.
  1009.  */
  1010. void rexxcolor(msg, p)
  1011. struct RexxMsg *msg ;
  1012. char *p ;
  1013. {
  1014.    parseargs(p, 1) ;
  1015.    currrexxcolor = args[0] ;
  1016. }
  1017. /*
  1018.  *   This function silently clips the x and y values at `n' to the
  1019.  *   window bounds.
  1020.  */
  1021. void clipxy(n)
  1022. int n ;
  1023. {
  1024.    if (args[n] < MinX)
  1025.       args[n] = MinX ;
  1026.    if (args[n] > MaxX)
  1027.       args[n] = MaxX ;
  1028.    n++ ;
  1029.    if (args[n] < MinY)
  1030.       args[n] = MinY ;
  1031.    if (args[n] > MaxY)
  1032.       args[n] = MaxY ;
  1033. }
  1034. /*
  1035.  *   This handler grabs four arguments and draws a box.
  1036.  */
  1037. void rexxbox(msg, p)
  1038. struct RexxMsg *msg ;
  1039. char *p ;
  1040. {
  1041.    parseargs(p, 4) ;
  1042.    clipxy(0) ;
  1043.    clipxy(2) ;
  1044.    DrawBox(args[0], args[1], args[2], args[3], Window, currrexxcolor) ;
  1045. }
  1046. /*
  1047.  *   This handler grabs four arguments and draws a filled box.
  1048.  */
  1049. void rexxfbox(msg, p)
  1050. struct RexxMsg *msg ;
  1051. char *p ;
  1052. {
  1053.    register int t ;
  1054.  
  1055.    parseargs(p, 4) ;
  1056.    clipxy(0) ;
  1057.    clipxy(2) ;
  1058.    if (args[0] > args[2]) {
  1059.       t = args[0] ; args[0] = args[2] ; args[2] = t ;
  1060.    }
  1061.    if (args[1] > args[3]) {
  1062.       t = args[1] ; args[1] = args[3] ; args[3] = t ;
  1063.    }
  1064.    RectFill( Window->RPort, (long)args[0], (long)args[1],
  1065.                             (long)args[2], (long)args[3]) ;
  1066. }
  1067. /*
  1068.  *   This handler grabs four arguments and draws a line.
  1069.  */
  1070. void rexxline(msg, p)
  1071. struct RexxMsg *msg ;
  1072. char *p ;
  1073. {
  1074.    parseargs(p, 4) ;
  1075.    clipxy(0) ;
  1076.    clipxy(2) ;
  1077.    Move(Window->RPort, (long)args[0], (long)args[1]) ;
  1078.    Draw(Window->RPort, (long)args[2], (long)args[3]) ;
  1079. }
  1080. /*
  1081.  *   This handler pops the window to front.
  1082.  */
  1083. void rexxtofront(msg, p)
  1084. struct RexxMsg *msg ;
  1085. char *p ;
  1086. {
  1087.    WindowToFront(Window) ;
  1088. }
  1089. /*
  1090.  *   This handler pops the window to back.
  1091.  */
  1092. void rexxtoback(msg, p)
  1093. struct RexxMsg *msg ;
  1094. char *p ;
  1095. {
  1096.    WindowToBack(Window) ;
  1097. }
  1098. /*
  1099.  *   This handler sets the exit flag.
  1100.  */
  1101. void rexxexit(msg, p)
  1102. struct RexxMsg *msg ;
  1103. char *p ;
  1104. {
  1105.    KeepGoing = 0 ;
  1106. }
  1107. /*
  1108.  *   This handler returns the version of the program.
  1109.  */
  1110. void rexxversion(msg, p)
  1111. struct RexxMsg *msg ;
  1112. char *p ;
  1113. {
  1114.    userreplied = 1 ;
  1115.    replyRexxCmd(msg, 0L, 0L, VERSION) ;
  1116. }
  1117. /*
  1118.  *   This handler sends the rest of the command asynchronously,
  1119.  *   allowing us to run macros in parallel.
  1120.  */
  1121. void rexxspawn(msg, p)
  1122. struct RexxMsg *msg ;
  1123. char *p ;
  1124. {
  1125.    while (*p <= ' ' && *p)
  1126.       p++ ;
  1127.    asyncRexxCmd(p) ;
  1128. }
  1129. #endif
  1130.